package com.zjlab.web.controller;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.StreamProgress;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpUtil;
import com.zjlab.SmConfig;
import com.zjlab.georeceive.GeoProcessor;
import com.zjlab.georeceive.bean.AreaBase;
import com.zjlab.sandtable.MfProcessor;
import com.zjlab.sandtable.SandTableUdp;
import com.zjlab.sandtable.bean.*;
import com.zjlab.web.bean.*;
import com.zjlab.web.config.ThreadPoolUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 中间件请求
 *
 * @author xue
 * @create 2022-11-03 11:00
 */
@Slf4j
@RestController
@RequiredArgsConstructor
public class DeskTopController {

    private final SmConfig smConfig;
    private final GeoProcessor geoProcessor;
    private final MfProcessor mfProcessor;
    private final SandTableUdp sandTableUdp;

    @PostMapping("/geo/status")
    public R geoStatus(@RequestBody GeoStatus geoStatus) {
        if (geoStatus.getOpen()) {
            if (!FileUtil.exist(smConfig.getImageFilePath())) {
                FileUtil.mkdir(smConfig.getImageFilePath());
            }
            HttpUtil.downloadFile(smConfig.getDeskTopRemoteUrl() + geoStatus.getUrl(), FileUtil.file(smConfig.getImageFilePath()), new StreamProgress() {
                @Override
                public void start() {
                }

                @Override
                public void progress(long l, long l1) {
                }

                @Override
                public void finish() {
                    // 发送投影图片
                    String url = geoStatus.getUrl();
                    String fileName = url.substring(url.lastIndexOf("/") + 1);
                    sandTableUdp.sendInfo(new ProjectionInfo(smConfig.getProjectionUrlHead() + fileName));
                    geoProcessor.geoSwitch(true);
                }
            });
            return R.ok();
        }
        geoProcessor.geoSwitch(false);
        return R.ok();
    }

    @PostMapping("/geo/simulationGeo")
    public R simulationGeo(@RequestBody AreaBase areaBase) {
        geoProcessor.receiveAreaBase(areaBase);
        return R.ok();
    }

    private static final Map<String, String> ADDRESS_URL_MAP = new HashMap<String, String>() {{
        put("oa", "http://192.168.1.200:8080/smallScreenDisplay/OA.jpg");
        put("gitlab", "http://192.168.1.200:8080/smallScreenDisplay/gitlab.png");
        put("gitlabInside", "http://192.168.1.200:8080/smallScreenDisplay/gitlab2.png");
        put("knowledgeIPv4", "http://192.168.1.200:8080/smallScreenDisplay/confluence.png");
        put("knowledgeIPv6", "http://192.168.1.200:8080/smallScreenDisplay/confluence.png");
        put("close", "");
    }};

    @PostMapping("/ip")
    public R ipModal(@RequestBody IpModal ipModal) {
        String address = ipModal.getAddress();
        sandTableUdp.sendInfo(new WebSiteAddress(ADDRESS_URL_MAP.get(address)));
        return R.ok();
    }

    @PostMapping("/make")
    public R make(@RequestBody CoinsMake coinsMake) {
        sandTableUdp.sendInfo(new CoinsMakeInfo(coinsMake.getTitle(), coinsMake.getCount()));
        return R.ok();
    }

    private static ThreadPoolExecutor ndnPool;
    private static final Integer TIME_LATE = 200;

    private static final Map<Integer, List<Integer>> NDN_DESCRIBE_MAP = new HashMap<Integer, List<Integer>>() {{
        // 市场部
        put(1, Arrays.asList(0b1000_0000_0000, 0b0100_0000_0000));
        // 运营部
        put(2, Arrays.asList(0b0010_0000_0000, 0b0001_0000_0000));
        // 产品部
        put(3, Arrays.asList(0b0000_1000_0000, 0b0000_0100_0000));
        // 质检部
        put(4, Arrays.asList(0b0000_0010_0000, 0b0000_0001_0000));
        // 监控部
        put(5, Arrays.asList(0b0000_0000_1000, 0b0000_0000_0100));
    }};

    @PostMapping("/ndn")
    public R ndnDescribe(@RequestBody NdnDescribe ndnDescribe) {
        // 新指令一定要关闭之前的执行线程
        if (ObjectUtil.isNotNull(ndnPool)) {
            ndnPool.shutdownNow();
        }
        // 新指令都需要关闭之前的所有
        sandTableUdp.sendInfo(new NdnLampInfo(to12IntString(0)));
        // 切换时候的关闭所有指令，无需继续运行
        if (ObjectUtil.isNull(ndnDescribe.getHistory()) && ObjectUtil.isNull(ndnDescribe.getDepartment())) {
            return R.ok();
        }
        ndnPool = ThreadPoolUtils.getThreadPool(1, 1, "ndn亮灯");
        // 旧位置为空，则一定是远程请求，闪烁远程过程，并结束运行
        if (ObjectUtil.isNull(ndnDescribe.getHistory())) {
            ndnPool.execute(() -> {
                List<Integer> lightList = NDN_DESCRIBE_MAP.get(ndnDescribe.getDepartment());
                int lightMessage = 0;
                lightMessage = lightMessage | 0b0000_0000_0010;
                sandTableUdp.sendInfo(new NdnLampInfo(to12IntString(lightMessage)));
                ndnSleep(TIME_LATE);
                lightMessage = lightMessage | 0b0000_0000_0001;
                sandTableUdp.sendInfo(new NdnLampInfo(to12IntString(lightMessage)));
                for (Integer item : lightList) {
                    ndnSleep(TIME_LATE);
                    lightMessage = lightMessage | item;
                    sandTableUdp.sendInfo(new NdnLampInfo(to12IntString(lightMessage)));
                }
            });
            return R.ok();
        }

        // 整合所有旧位置的亮灯，有旧位置，则一定是有远程灯带显示的
        AtomicInteger lightMessage = new AtomicInteger(0b0000_0000_0011);
        for (Integer historyItem : ndnDescribe.getHistory()) {
            for (Integer item : NDN_DESCRIBE_MAP.get(historyItem)) {
                lightMessage.set(lightMessage.get() | item);
            }
        }
        // 如果新位置为空，则是页面切换，直接结束
        if (ObjectUtil.isNull(ndnDescribe.getDepartment())) {
            sandTableUdp.sendInfo(new NdnLampInfo(to12IntString(lightMessage.get())));
            return R.ok();
        }
        // 闪烁短距离的灯光
        ndnPool.execute(() -> {
            List<Integer> items = NDN_DESCRIBE_MAP.get(ndnDescribe.getDepartment());
            lightMessage.set(lightMessage.get() | items.get(0));
            sandTableUdp.sendInfo(new NdnLampInfo(to12IntString(lightMessage.get())));
            ndnSleep(TIME_LATE);
            lightMessage.set(lightMessage.get() | items.get(1));
            sandTableUdp.sendInfo(new NdnLampInfo(to12IntString(lightMessage.get())));
        });
        return R.ok();
    }

    @PostMapping("/ndn/close")
    public R closeNdn() {
        if (ObjectUtil.isNotNull(ndnPool)) {
            ndnPool.shutdownNow();
        }
        sandTableUdp.sendInfo(new NdnLampInfo(to12IntString(0)));
        return R.ok();
    }

    private String to12IntString(int input) {
        return String.format("%12s", Integer.toBinaryString(input)).replace(" ", "0");
    }

    private void ndnSleep(int millis) {
        try {
            TimeUnit.MILLISECONDS.sleep(millis);
        } catch (InterruptedException e) {
            log.error("ndn亮灯被打断", e);
        }
    }

    @PostMapping("/mf/status")
    public R mfStatus(@RequestBody MfStatus mfStatus) {
        if (mfStatus.getOpen()) {
            mfProcessor.mfSwitch(true);
            sandTableUdp.sendInfo(new MfStatusInfo(3));
        } else {
            mfProcessor.mfSwitch(false);
            sandTableUdp.sendInfo(new MfStatusInfo(2));
        }
        return R.ok();
    }

    @PostMapping("/mf/model")
    public R mfModel(@RequestBody MfModel mfModel) {
        if (mfModel.getModel().equals(1)) {
            sandTableUdp.sendInfo(new MfModelInfo(mfModel.getModel()));
        }
        return R.ok();
    }

    private final static AtomicInteger CACHE_MODE_ID = new AtomicInteger(0);

    @PostMapping("/modeSwitch")
    public R modeSwitch(@RequestBody Mode mode) {
        // 无论之前是什么都要重置模态
        sandTableUdp.sendInfo(new ModeInfo(mode.getModeId()), smConfig.getSandTableScreenAddress());
        // 和之前一致，不需要下面的判断了
        int beforeModeId = CACHE_MODE_ID.get();
        if (mode.getModeId().equals(beforeModeId)) {
            return R.ok();
        }
        // 如果这次是mf，开启投影
        if (ModeEnum.MF.getModeId().equals(mode.getModeId())) {
            sandTableUdp.sendInfo(new MfStatusInfo(1));
        }
        // 如果之前是mf，需要关闭小车和投影
        if (ModeEnum.MF.getModeId().equals(beforeModeId)) {
            mfProcessor.mfSwitch(false);
            sandTableUdp.sendInfo(new MfStatusInfo(2));
            sandTableUdp.sendInfo(new MfStatusInfo(4));
        }
        // 更新历史记录
        CACHE_MODE_ID.set(mode.getModeId());
        return R.ok();
    }

    @PostMapping("/mediaControl")
    public R mediaControl(@RequestBody MediaId mediaId) {
        // 1 视频 2 图片
        String fileName = ModeEnum.getResourceByModeId(CACHE_MODE_ID.get()).get(mediaId.getButtonId() - 1);
        // 1 视频 2 图片
        sandTableUdp.sendInfo(new MediaInfo(fileName, mediaId.getButtonId()), smConfig.getSandTableScreenAddress());
        return R.ok();
    }

    @PostMapping("/screenShow")
    public R screenShow(@RequestBody ScreenShowInfo screenShowInfo) {
        sandTableUdp.sendInfo(screenShowInfo);
        return R.ok();
    }

    @PostMapping("/carSpeed")
    public R carSpeed(@RequestBody CarSpeedRequestInfo carSpeedRequestInfo) {
        sandTableUdp.sendInfo(carSpeedRequestInfo);
        return R.ok();
    }

    @PostMapping("/carSpeedSetInfo")
    public R carSpeed(@RequestBody CarSpeedSetInfo carSpeedSetInfo) {
        sandTableUdp.sendInfo(carSpeedSetInfo);
        return R.ok();
    }

}
